<template>
  <div class="td-box" ref="can"></div>
</template>
<script setup>
import { onMounted, ref, onBeforeUnmount, computed, watch } from "vue";
import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import editStore from "@/store/editStore";
import { getAssetsFile } from "@/utils/index.js";
import { debounce } from "@/utils";

let props = defineProps({
  from: {
    type: String,
    default: "",
  },
  storeJson: {
    type: Object,
    default: () => {},
  },
});

const store = computed(() => {
  return props.from == "home" ? props.storeJson : editStore();
});

let frameId = null; //旋转动作id
let can = ref();
let render = null;
let controls = null;
let camera = null;
let scene = new THREE.Scene();
let mesh = null;
let pkg = null;
let currentPackage = null;

let loader = new THREE.TextureLoader();
loader.setCrossOrigin("Anonymous");

let AmbientLight = new THREE.AmbientLight("#fff", 1);
scene.add(AmbientLight);

function init() {
  pkg = store.value.packageConfig;
  currentPackage = store.value.packageConfig.packageList[store.value.reelIndex];

  let geometry = new THREE.BoxGeometry(pkg.bagWidth, 2, pkg.bagHeigh);

  let pkgFrontImg = pkg.frontImg ? pkg.frontImg : getAssetsFile("package");

  let ftexture = loader.load(pkgFrontImg, () => {
    render.render(scene, camera);
  });

  let Material1 = new THREE.MeshBasicMaterial({
    map: ftexture,
    side: THREE.DoubleSide,
  });
  let pkgOppoImg = pkg.oppositeImg ? pkg.oppositeImg : getAssetsFile("package");
  let Material2 = new THREE.MeshBasicMaterial({
    map: loader.load(pkgOppoImg),
  });
  let Material3 = new THREE.MeshBasicMaterial({
    color: "#fff",
  });
  let maters = [
    Material3,
    Material3,
    Material1,
    Material2,
    Material3,
    Material3,
  ];

  mesh = new THREE.Mesh(geometry, maters);
  mesh.position.set(0, 0, 0);

  if (pkg.hasESD) {
    let size = pkg.esdSize || 60;
    let label = new THREE.PlaneGeometry(size, size);
    let texture = loader.load(getAssetsFile("esd"));
    let mater = new THREE.MeshBasicMaterial({
      map: texture,
      side: THREE.DoubleSide,
    });
    let zIndex = pkg.esdSizeInBag == 0 ? 2 : -2;
    let esd = new THREE.Mesh(label, mater);
    esd.position.set(
      pkg.esdPositionX - pkg.bagWidth / 2 + size / 2,
      zIndex,
      pkg.esdPositionY - pkg.bagHeigh / 2 + size / 2
    );
    esd.rotation.set(-Math.PI / 2, 0, -(pkg.esdPositionR / 180) * Math.PI);
    mesh.add(esd);
  }

  scene.add(mesh);

  currentPackage.frontComponentList.forEach((item) => {
    if (item.type == "Labels") {
      createPlaneGeometry(item, "front");
    }
  });
  currentPackage.oppositeComponentList.forEach((item) => {
    if (item.type == "Labels") {
      createPlaneGeometry(item, "opposite");
    }
  });
}

init();

function createPlaneGeometry(item, type) {
  let label = new THREE.PlaneGeometry(item.length, item.width);
  let texture = loader.load(item.picName, () => {
    render.render(scene, camera);
  });
  let material = new THREE.MeshBasicMaterial({
    map: texture,
    side: THREE.DoubleSide,
  });
  let lmesh = new THREE.Mesh(label, material);
  let yIndex = 2;
  yIndex = type == "front" ? yIndex : yIndex * -1;
  lmesh.position.set(
    item.x - pkg.bagWidth / 2 + item.length / 2,
    yIndex,
    item.y - pkg.bagWidth / 2 + item.width / 2
  );
  lmesh.rotation.set(-Math.PI / 2, 0, -(item.angle / 180) * Math.PI);
  mesh.add(lmesh);
  if (item.qaStamp) {
    createCircleGeometry(item, type, lmesh);
  }
}

function createCircleGeometry(item, type, label) {
  let r = (item.qaSize || 12) / 2;
  let qa = new THREE.CircleGeometry(r);
  let texture = loader.load(getAssetsFile("QA"));
  let material = new THREE.MeshBasicMaterial({
    map: texture,
    side: THREE.DoubleSide,
  });
  let lmesh = new THREE.Mesh(qa, material);
  // lmesh.position.set(item.qaStampx + r, item.qaStampy - item.width + r, 1);
  lmesh.position.set(
    item.qaStampX - item.length / 2 + r,
    -item.qaStampY + item.width / 2 - r,
    1
  );
  lmesh.rotation.set(0, 0, (item.qaStampAngle / 180) * Math.PI);
  label.add(lmesh);
}

function action() {
  mesh.rotation.x += 0.001;
  mesh.rotation.y += 0.001;
  mesh.rotation.z += 0.001;
  render.render(scene, camera);
  frameId = requestAnimationFrame(action);
}

function resize() {
  render.setSize(can.value.offsetWidth, can.value.offsetHeight); // 根据缩放的窗口重新设置画布的大小
  // 垂直相机宽高比
  camera.aspect = can.value.offsetWidth / can.value.offsetHeight;
  // 更新相机投影矩阵
  camera.updateProjectionMatrix();
}
let debResize = debounce(resize, 100);

onMounted(() => {
  camera = new THREE.PerspectiveCamera(
    30,
    can.value.offsetWidth / can.value.offsetHeight,
    1,
    5000
  );
  camera.lookAt(0, 0, 0);
  camera.position.set(0, pkg.bagWidth * 3, 0);
  render = new THREE.WebGLRenderer({
    alpha: true,
    antialias: true,
  });
  render.setSize(can.value.offsetWidth, can.value.offsetHeight);
  render.setPixelRatio(window.devicePixelRatio);

  controls = new OrbitControls(camera, render.domElement);
  controls.addEventListener("change", () => {
    render.render(scene, camera);
  });
  can.value.appendChild(render.domElement);
  if (props.from == "home") {
    action();
  } else {
    render.render(scene, camera);
  }
  window.addEventListener("resize", debResize);
});

onBeforeUnmount(() => {
  if (props.from == "home") {
    frameId && cancelAnimationFrame(frameId);
  }
  window.removeEventListener("resize", debResize);

  render.dispose();
  controls = null;
  render = null;
  camera = null;
  scene = null;
});

watch(
  () => props.storeJson,
  () => {
    scene.remove(mesh);
    mesh.geometry.dispose();
    init();
    render.render(scene, camera);
  }
);
</script>
<style scoped lang="scss">
.td-box {
  width: 100%;
  height: 100%;
}
</style>
